
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using Swaf.BizRule;

namespace Swaf.Security
{
	/// <summary>
	/// The SecurityRuleDecorator class implements the IRuleDecorator interface and is 
	/// registered in the RuleDecorators classfactory in the SecurityFeature file.  
	/// This decorator is automatically added to all business rules during startup 
	/// configuration unless the rule definition already has it defined.  To decorate 
	/// a rule to override the default behavior of security, add the security attribute 
	/// to the rule definition.  Valid values are true (the default if the decorator is 
	/// not explicitly declared), false for no security or global to use the default 
	/// security principal on the global application object.
	/// </summary>
	public class SecurityRuleDecorator : IRuleDecorator	
	{
		protected string m_name="";
		
		/// <summary>
		/// Enumeration containing the valid values for this decorator.
		/// </summary>
		/// <remarks>
		/// <p>disabled - indicates that no security should be applied to this rule</p>
		/// <p>enabled - indicates that security should be applied using the current principal</p>
		/// <p>global - indicates that security should be applied using the current principal on the global application</p>
		/// </remarks>
		protected enum State
		{
			disabled = 0,
			enabled = 1,
			global = 2
		}
		protected State m_state = State.enabled;

		/// <summary>
		/// Constructor for this decorator
		/// </summary>
		/// <param name="name"></param>
		/// <param name="val"></param>
		/// <param name="extraInfo"></param>
		public SecurityRuleDecorator(string name, string val, object extraInfo)
		{
			m_name = name;
			string state = val.ToLower();

			try
			{
				m_state = (State) State.Parse(typeof(State),state);
			}
			catch(Exception e)
			{
				throw new BaseException(string.Format("Unable to set decorator {0} to a value of {1}", name,val));
			}
		}
		#region IRuleDecorator Members

		/// <summary>
		/// Called by the QueueElement prior to rule execution.  This method actuall implements the
		/// security call.  It performs a security assertion against the security principal (if enabled)
		/// using the Privileges.Execute enum as the minimum required privilige. 
		/// </summary>
		/// <param name="info"></param>
		/// <returns></returns>
		public bool preRuleExecution(IRunningRule info)
		{
			if (m_state == State.enabled)
			{
				//We need to store a reference to the current app and reset it after the call to get privaleges
				//just in case get privalege calls a rule that resets the app.
				IApplication thisApp = Application.currentApp;
				
				//Use the assert method to test for privileges for the current principal for this rule
				//if the user does not have access, an AccessDenied exception will be thrown and audited.
				Application.currentApp.securityMgr.currentPrincipal.assert("BizRules." + info.Info.Name,Privileges.Execute);

				//Reset the app.
				Application.currentApp=thisApp;

			}
			else if (m_state == State.global)
			{
				Application.globalApp.securityMgr.currentPrincipal.assert("BizRules." + info.Info.Name,Privileges.Execute);
			}
			return true;
		}

		/// <summary>
		/// Not implemented.
		/// </summary>
		/// <param name="info"></param>
		/// <param name="ruleReturn"></param>
		/// <param name="ruleException"></param>
		public void postRuleExecution(IRunningRule info, ref object ruleReturn, ref Exception ruleException)
		{
		}

		#endregion

		#region IDecorator Members

		/// <summary>
		/// <see cref="IDecorator.decorateInstance"/>
		/// </summary>
		/// <param name="theInst"></param>
		/// <returns></returns>
		public object decorateInstance(object theInst)
		{
			return theInst;
		}

		/// <summary>
		/// Returns the value of the security attribute on the rule.
		/// </summary>
		public string Value
		{
			get
			{
				return m_state.ToString();
			}
		}

		/// <summary>
		/// Returns the name of the decorator (security)
		/// </summary>
		public string Name
		{
			get
			{
				return m_name;
			}
		}

		/// <summary>
		/// <see cref="IDecorator.IsStandin"/>
		/// </summary>
		public bool IsStandin
		{
			get
			{
				return true;
			}
		}

		#endregion
	}
}
